/******************* ?Marvell Semiconductor, Inc., 2001-2004 *****************
 *
 *  Purpose:    This module has the implementaion of RX routines
 *
 *  $Author: schiu $
 *
 *  $Date: 2004/10/29 $
 *
 *  $Revision: #6 $
 *
 *****************************************************************************/

/*
===============================================================================
            INCLUDE FILES
===============================================================================
*/
#include "precomp.h"
#include "pkfuncs.h"
#include "rxproc.h"
#include "If.h"
#include "wlan_thread.h"

typedef struct _RX_PARAM
{
	UCHAR                               pRxBuf[(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE)*2];
	ULONG                               ulRxSize;
	NDIS_HANDLE                         RxPacketPoolHandle;
	NDIS_HANDLE                         RxBufferPoolHandle;
	PACKET_QUEUE_NODE                   RxPacketQueueNode[MRVDRV_NUM_RX_PKT_IN_QUEUE];
	NDIS_SPIN_LOCK                      RxQueueSpinLock;
	Q_KEEPER                            RxPacketFreeQueue;
	SHORT                             sNumOutstandingRxPacket;
    PPACKET_QUEUE_NODE                  pTmpPendRxNode;
    PPACKET_QUEUE_NODE                  pCurrRxNode;
    NDIS_STATUS                         PktStatus; 
    ULONG                               indicateevent;
    ///PendNode ++
    //{
    NDIS_SPIN_LOCK		                RxCS;
    PNDIS_EVENT				            hIndicateEvent;
    PNDIS_PACKET                        pRxPendPkts[MRVDRV_NUM_RX_PKT_IN_QUEUE*RxPKTAggreCnt];
    USHORT                              PRPktCount;         ///Pending_Rx_Packet Count
    USHORT                              PRNdCount;          ///Pending Rx Node Count
    PPACKET_QUEUE_NODE                  pPendingRxNode[MRVDRV_NUM_RX_PKT_IN_QUEUE];
    //}
    ///PendNode --
    
	///	
	PMRVDRV_ADAPTER			pAdapter;
	NDIS_HANDLE             MrvDrvAdapterHdl;

} RX_PARAM, *PRX_PARAM;

static RX_PARAM	RxParam[1];


static NDIS_STATUS AllocateRxQ(IN PRX_PARAM);
static NDIS_STATUS FreeRxQ(IN PRX_PARAM);

///PendNode ++
static void RxIndicateThread(PVOID pContext);
///PendNode --   



VOID
wlan_compute_rssi(PMRVDRV_ADAPTER Adapter, PRxPD   pRxPDCurrent);

/******************************************************************************
 *
 *  Name: AllocateRxQ()
 *
 *  Description: Allocate Rx Buffer
 *
 *  Arguments:  PMRVDRV_ADAPTER Adapter
 *    
 *  Return Value: NDIS_STATUS_SUCCESS or NDIS_STATUS_FAILURE
 * 
 *  Notes:        
 *
 *****************************************************************************/
static NDIS_STATUS AllocateRxQ(
  IN PRX_PARAM pRxParam
  )
{
    ULONG i, j;
    NDIS_STATUS tStatus;
    BOOLEAN                 bSuccess = TRUE;
    PACKET_QUEUE_NODE       **pNode;
    PNDIS_PACKET_OOB_DATA   pOOB; 

    /// Initialize rx-related variables 
    pRxParam->RxBufferPoolHandle = 
    pRxParam->RxPacketPoolHandle = NULL;
    //
    InitializeQKeeper(&pRxParam->RxPacketFreeQueue);
    // 
	NdisZeroMemory(pRxParam->RxPacketQueueNode, sizeof(PACKET_QUEUE_NODE)*MRVDRV_NUM_RX_PKT_IN_QUEUE);

    /// Allocate all needed memory space 
    do
    {
        // packet pool 
        NdisAllocatePacketPoolEx(
                                &tStatus, 
                                &pRxParam->RxPacketPoolHandle,
                                MRVDRV_NUM_RX_PKT_IN_QUEUE*RxPKTAggreCnt,
                                MRVDRV_NUM_RX_PKT_IN_QUEUE*RxPKTAggreCnt, 
                                PROTOCOL_RESERVED_SIZE_IN_PACKET);
        if ( tStatus != NDIS_STATUS_SUCCESS )
        {
            DBGPRINT(DBG_LOAD | DBG_ERROR,
                    (L"Unable to allocate packet pool!\n"));
            return tStatus;
        }

        // buffer pool 
        NdisAllocateBufferPool(
                               &tStatus,
                               &pRxParam->RxBufferPoolHandle,
                               MRVDRV_NUM_RX_PKT_IN_QUEUE*RxPKTAggreCnt);
        if ( tStatus != NDIS_STATUS_SUCCESS )
        {
            DBGPRINT(DBG_LOAD | DBG_ERROR,
                    (L"Unable to allocate buffer pool!\n"));
            bSuccess = FALSE;
            break;
        }

        // assign space to used three array 
        for ( i=0; i < MRVDRV_NUM_RX_PKT_IN_QUEUE; i++ )
        {
			PPACKET_QUEUE_NODE	pRxNode = &pRxParam->RxPacketQueueNode[i];
            // data payload space array 
            tStatus = NdisAllocateMemoryWithTag(
                         &pRxNode->pRxBufVM, 
                         MRVDRV_ETH_RX_PACKET_BUFFER_SIZE,
                         MRVDRV_MEMORY_TAG);
            //to hide unused packet header ahead of pointer.   
            (ULONG)pRxNode->pRxBufVM += MRVDRV_ETH_RX_HIDDEN_HEADER_SIZE;
            if ( tStatus != NDIS_STATUS_SUCCESS )
            {
                bSuccess = FALSE;
                break;
            }
                      
            // packet array   
			for (j=0 ; j<RxPKTAggreCnt ; j++) {
				NdisAllocatePacket(
								   &tStatus, 
								   &pRxNode->pPacket[j],
								   pRxParam->RxPacketPoolHandle);
				if ( tStatus != NDIS_STATUS_SUCCESS )
				{
					bSuccess = FALSE;
					break;
				}
				// init OBB space
				pOOB = NDIS_OOB_DATA_FROM_PACKET(pRxNode->pPacket[j]);
				NdisZeroMemory(pOOB, sizeof(NDIS_PACKET_OOB_DATA));
				NDIS_SET_PACKET_HEADER_SIZE(pRxNode->pPacket[j], MRVDRV_ETH_HEADER_SIZE);
                pNode = (PACKET_QUEUE_NODE **)pRxNode->pPacket[j]->MiniportReserved;
				*pNode = pRxNode;
			}
            
            // insert to free queue
            InsertQNodeAtTail(&pRxParam->RxPacketFreeQueue, &pRxParam->RxPacketQueueNode[i]);

        }   // end of for(;;)
    } while (0);

    if ( ! bSuccess )
    {
        // clean up all
        FreeRxQ(pRxParam);
        return NDIS_STATUS_FAILURE;
    }

    pRxParam->sNumOutstandingRxPacket = 0;

    return NDIS_STATUS_SUCCESS;
}

/******************************************************************************
 *
 *  Name: FreeRxQ()
 *
 *  Description: Free Rx buffer
 *
 *  Arguments:  PMRVDRV_ADAPTER Adapter
 *    
 *  Return Value: NDIS_STATUS_SUCCESS or NDIS_STATUS_FAILURE
 * 
 *  Notes:        
 *
 *****************************************************************************/
static NDIS_STATUS FreeRxQ(
  IN PRX_PARAM pRxParam
  )
{
    ULONG i;
	USHORT j;
	PPACKET_QUEUE_NODE	pRxNode;

    DBGPRINT(DBG_BUF|DBG_RX|DBG_HELP,(L"Free Rx Q\r\n"));
   
    for ( i=0; i < MRVDRV_NUM_RX_PKT_IN_QUEUE; i++ )
    {
		pRxNode = &pRxParam->RxPacketQueueNode[i];
        if ( pRxNode->pRxBufVM != NULL )
        {                       
            (ULONG)pRxNode->pRxBufVM -= MRVDRV_ETH_RX_HIDDEN_HEADER_SIZE;
            NdisFreeMemory(pRxNode->pRxBufVM,
                           MRVDRV_ETH_RX_PACKET_BUFFER_SIZE,
                           0);            
            pRxNode->pRxBufVM = NULL;
        }

		for (j=0 ; j<RxPKTAggreCnt ; j++) {
			if ( pRxNode->pRxBuffer[j] != NULL )
			{
				NdisFreeBuffer(pRxNode->pRxBuffer[j]);
				pRxNode->pRxBuffer[j] = NULL;
			}

			if ( pRxNode->pPacket[j] != NULL )
			{
				NdisFreePacket(pRxNode->pPacket[j]);
				pRxNode->pPacket[j] = NULL;
			}
		}
    } 
    
    if ( pRxParam->RxBufferPoolHandle != NULL )
    {
        NdisFreeBufferPool(pRxParam->RxBufferPoolHandle);
        pRxParam->RxBufferPoolHandle = NULL;
    }

    if ( pRxParam->RxPacketPoolHandle != NULL )
    {
        NdisFreePacketPool(pRxParam->RxPacketPoolHandle);
        pRxParam->RxPacketPoolHandle = NULL;
    }
    return NDIS_STATUS_SUCCESS;
}

/******************************************************************************
 *
 *  Name: ResetRxPDQ()
 *
 *  Description: RxPDQ reset
 *
 *  Arguments:  PMRVDRV_ADAPTER Adapter
 *    
 *  Return Value:        
 * 
 *
 *****************************************************************************/
VOID
ResetRxPDQ(IN PVOID ipRxParam)
{
	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
	ULONG i;
	  
	NdisAcquireSpinLock(&pRxParam->RxQueueSpinLock);

	pRxParam->sNumOutstandingRxPacket = 0;
	InitializeQKeeper(&pRxParam->RxPacketFreeQueue);

	for ( i=0; i < MRVDRV_NUM_RX_PKT_IN_QUEUE; i++ )
	    InsertQNodeAtTail(&pRxParam->RxPacketFreeQueue, &pRxParam->RxPacketQueueNode[i]);

	NdisReleaseSpinLock(&pRxParam->RxQueueSpinLock);
	return;
}

PPACKET_QUEUE_NODE
GetRxNode(IN PVOID ipRxParam)
{
	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
    PPACKET_QUEUE_NODE  pPacketNode = NULL;

    NdisAcquireSpinLock(&pRxParam->RxQueueSpinLock);

    if ( pRxParam->sNumOutstandingRxPacket == MRVDRV_NUM_RX_PKT_IN_QUEUE )
    {
        NdisReleaseSpinLock(&pRxParam->RxQueueSpinLock);
		DBGPRINT(DBG_RX|DBG_ERROR, (L"%s: sNumOutstandingRxPacket : %d\r\n", TEXT(__FUNCTION__), pRxParam->sNumOutstandingRxPacket ));
        RETAILMSG(1, (L"%s: sNumOutstandingRxPacket : %d\r\n", TEXT(__FUNCTION__), pRxParam->sNumOutstandingRxPacket ));
        goto FuncFinal;
    }

    // get a free packet 
    pPacketNode = (PPACKET_QUEUE_NODE)PopFirstQNode(&pRxParam->RxPacketFreeQueue);  
    pRxParam->sNumOutstandingRxPacket++;

    NdisReleaseSpinLock(&pRxParam->RxQueueSpinLock);
//RETAILMSG(1, (L"%s: %d\r\n", TEXT(__FUNCTION__), pRxParam->sNumOutstandingRxPacket));
    DBGPRINT(DBG_RX|DBG_HELP, (L"Packet 0x%x allocated, NumOutstandingRxPacket = %d\n", 
                               pPacketNode->pPacket,
                               pRxParam->sNumOutstandingRxPacket));
FuncFinal:
    return pPacketNode;
}
/******************************************************************************
 *
 *  Name: ReturnRxPacketDesc()
 *
 *  Description: Return a RX Packet descriptor
 *
 *  Arguments:  PMRVDRV_ADAPTER Adapter
 *    
 *  Return Value: NONE
 * 
 *  Notes:        
 *
 *****************************************************************************/
__inline VOID
ReturnRxPacketDesc(IN PVOID ipRxParam,
                   PNDIS_PACKET    pPacket)
{
	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
    PPACKET_QUEUE_NODE  pPacketNode = *((PACKET_QUEUE_NODE **)pPacket->MiniportReserved);
    USHORT      i;

    NdisAcquireSpinLock(&pRxParam->RxQueueSpinLock);
    for (i=0 ; i<RxPKTAggreCnt ; i++) {
        if (pPacketNode->pPacket[i] == pPacket) {
            break;
        }
    }
    if (i == RxPKTAggreCnt) {
        RETAILMSG(1, (L"Fatal Error: %s, can't find available packet\r\n", TEXT(__FUNCTION__)));
        goto FuncFinal;
    }
    ASSERT(pPacketNode->pRxBuffer[i] != NULL);

    NdisUnchainBufferAtFront(pPacketNode->pPacket[i], &pPacketNode->pRxBuffer[i]);
	NdisFreeBuffer(pPacketNode->pRxBuffer[i]);
    pPacketNode->pRxBuffer[i] = NULL;
    pPacketNode->UsedPkt --;
///RETAILMSG(1, (L"%s: %d, %d\r\n", TEXT(__FUNCTION__), pPacketNode->UsedPkt, pRxParam->sNumOutstandingRxPacket));
    if (pPacketNode->UsedPkt == 0) {
        InsertQNodeFromHead(&pRxParam->RxPacketFreeQueue, pPacketNode);
        pRxParam->sNumOutstandingRxPacket--;
    }

    if ( pRxParam->sNumOutstandingRxPacket < 0 )
    {
        RETAILMSG(1, (L"%s: numOutstandingPacket already 0!!\n", TEXT(__FUNCTION__)));
        DBGPRINT(DBG_ERROR, (L"%s: numOutstandingPacket already 0!!\n", TEXT(__FUNCTION__)));
        //NdisReleaseSpinLock(&pRxParam->RxQueueSpinLock);
        //return;
        goto FuncFinal;
    }

    
    DBGPRINT(DBG_RX|DBG_HELP, (L"%s:PacketNode(0x%x) with Packet(0x%x) returned, NumOutstandingRxPacket = %d\n", 
							TEXT(__FUNCTION__),
                            pPacketNode,
                            pPacketNode->pPacket,
                            pRxParam->sNumOutstandingRxPacket));
FuncFinal:    
    NdisReleaseSpinLock(&pRxParam->RxQueueSpinLock);
    return;
}

VOID
ReturnRxPacketNode(IN PVOID ipRxParam,
                   PPACKET_QUEUE_NODE  pPacketNode)
{
	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
    USHORT      i;

    NdisAcquireSpinLock(&pRxParam->RxQueueSpinLock);
    pPacketNode->UsedPkt = 0;
    for (i=0 ; i<RxPKTAggreCnt ; i++) {
        pPacketNode->pRxBuffer[i] = NULL;
    }
    InsertQNodeFromHead(&pRxParam->RxPacketFreeQueue, pPacketNode);
    pRxParam->sNumOutstandingRxPacket--;
    if ( pRxParam->sNumOutstandingRxPacket < 0 )
    {
        RETAILMSG(1, (L"%s: numOutstandingPacket already 0!!\n", TEXT(__FUNCTION__)));
        DBGPRINT(DBG_ERROR, (L"%s: numOutstandingPacket already 0!!\n", TEXT(__FUNCTION__)));
        NdisReleaseSpinLock(&pRxParam->RxQueueSpinLock);
        return;
    }
//RETAILMSG(1, (L"%s: %d\r\n", TEXT(__FUNCTION__), pRxParam->sNumOutstandingRxPacket));
    DBGPRINT(DBG_RX|DBG_HELP, (L"%s:PacketNode(0x%x) with Packet(0x%x) returned, NumOutstandingRxPacket = %d\n", 
							TEXT(__FUNCTION__),
                            pPacketNode,
                            pPacketNode->pPacket,
                            pRxParam->sNumOutstandingRxPacket));
    
    NdisReleaseSpinLock(&pRxParam->RxQueueSpinLock);
}
/******************************************************************************
 *
 *  Name: wlan_compute_rssi()
 *
 *  Description: This function computes the RSSI in received packet
 *
 *  Arguments:  PMRVDRV_ADAPTER Adapter:  A pointer to wlan adapter structure
                        RxPD   pRxPDCurrent: A pointer to RxPD structure of received packet
 *    
 *  Return Value: NONE
 * 
 *  Notes:        
 *
 *****************************************************************************/
__inline 
VOID
wlan_compute_rssi(PMRVDRV_ADAPTER Adapter, PRxPD   pRxPDCurrent)
{

    DBGPRINT(DBG_RSSI|DBG_HELP ,(L"RxPD: SNR = %d, NF = %d\n", pRxPDCurrent->SNR, pRxPDCurrent->NF));
    DBGPRINT(DBG_RSSI|DBG_HELP ,(L"Before computing SNR and NF\n"));
    DBGPRINT(DBG_RSSI|DBG_HELP,(L"Adapter: SNR- avg = %d, NF-avg = %d\n", Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE));
  
     Adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = pRxPDCurrent->SNR;
     Adapter->NF[TYPE_RXPD][TYPE_NOAVG] = pRxPDCurrent->NF;
     Adapter->RxPDRate = pRxPDCurrent->RxRate;
     //Adapter->RxPDSNRAge = os_time_get();

      /* Average out the SNR from the received packet */
      Adapter->SNR[TYPE_RXPD][TYPE_AVG] =
        CAL_AVG_SNR_NF(Adapter->SNR[TYPE_RXPD][TYPE_AVG], pRxPDCurrent->SNR,Adapter->data_avg_factor);

      /* Average out the NF value */
      Adapter->NF[TYPE_RXPD][TYPE_AVG] = 
        CAL_AVG_SNR_NF(Adapter->NF[TYPE_RXPD][TYPE_AVG], pRxPDCurrent->NF, Adapter->data_avg_factor);
    
      DBGPRINT(DBG_RSSI|DBG_HELP ,(L"After computing SNR and NF\n"));
      DBGPRINT(DBG_RSSI|DBG_HELP ,(L"Adapter: SNR- avg = %d, NF-avg = %d\n", (Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE), (Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE)));

      Adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] = 
            (SHORT)CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
                Adapter->NF[TYPE_RXPD][TYPE_NOAVG]);

      Adapter->RSSI[TYPE_RXPD][TYPE_AVG] = 
            (SHORT)CAL_RSSI(Adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
                Adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);

    
      Adapter->ulRSSITickCount=GetTickCount();

      if ((Adapter->RSSI[TYPE_RXPD][TYPE_AVG] > -10) || (Adapter->RSSI[TYPE_RXPD][TYPE_AVG] < -200))
      {
    
         if(Adapter->MediaConnectStatus == NdisMediaStateConnected)
         {
          DBGPRINT(DBG_ERROR, (L"ERROR: Incorrect RSSI Value2 - SNR = %d, NF= %d, Adapter->RSSI[TYPE_RXPD][TYPE_AVG] = %d, Adapter->LastRSSI = %d\n", 
                               pRxPDCurrent->SNR, 
                               pRxPDCurrent->NF,
                               Adapter->RSSI[TYPE_RXPD][TYPE_AVG],
                               Adapter->LastRSSI));
         }
      
      }
      else
      {           
              Adapter->LastRSSI = (LONG)Adapter->RSSI[TYPE_RXPD][TYPE_AVG];                      
      }
        
       if (Adapter->LastRSSI <= Adapter->RSSITriggerValue)
        {
          // Increment RSSITriggerCounter
          Adapter->RSSITriggerCounter++;
        }
        else
        {
          // Reset the counter if RSSI goes above the trigger level
          if (Adapter->RSSITriggerCounter !=0)
            Adapter->RSSITriggerCounter=0;
        }
      
        // If the trigger occurs many times, send indication above
      if (Adapter->RSSITriggerCounter >= MRVDRV_RSSI_INDICATION_THRESHOLD)
        {     
          // Indicate to protocol driver about RSSI status
          NdisMIndicateStatus(Adapter->MrvDrvAdapterHdl,
                NDIS_STATUS_MEDIA_SPECIFIC_INDICATION,
                &(Adapter->LastRSSI),
                sizeof(LONG));
          NdisMIndicateStatusComplete(Adapter->MrvDrvAdapterHdl);
          // Reset the counter
          Adapter->RSSITriggerCounter=0;
    
        }

}



/******************************************************************************
 *
 *  Name: HandleRxReadyEvent()
 *
 *  Description: Rx ready event handler
 *
 *  Arguments:  PMRVDRV_ADAPTER Adapter
 *    
 *  Return Value:        
 * 
 *  Notes:               
 *
 *****************************************************************************/
static int RxStats[RxPKTAggreCnt+1];
VOID
HandleRxReadyEvent(IN PVOID ipRxParam)
{
	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
	PMRVDRV_ADAPTER Adapter = pRxParam->pAdapter;
    int           IsRxOK = 0;
    NDIS_STATUS   pStatus = NDIS_STATUS_RESOURCES;    /// NDIS_STATUS_SUCCESS
    PPACKET_QUEUE_NODE  pCurrRxNode = pRxParam->pCurrRxNode;
    USHORT  i; 

    {
    USHORT  statid;
	RxStats[pCurrRxNode->UsedPkt-1] ++;
	RxStats[RxPKTAggreCnt] ++;
	if (RxStats[RxPKTAggreCnt] >= 100000) {
		RETAILMSG(1, (L"RxAggr_Statistics: ("));
        for (statid=0 ; statid<RxPKTAggreCnt+1 ; statid++) {
            RETAILMSG(1, (L" %d, ", RxStats[statid]));
            RxStats[statid] = 0;
        }
        RETAILMSG(1, (L")\r\n"));
	}
    }
    DBGPRINT(DBG_RX | DBG_HELP,(L"+HandleRxReadyEvent()\n"));
/*
#ifdef SMALL_DEBUG
    if (pRxPDCurrent->RxPacketType == RX_PKT_TYPE_DEBUG)
    {
        PUCHAR        pRxPacketBuf = NULL;
        UCHAR         dbgType;

        pPacket = pRxParam->pRxCurPkt;
        pRxParam->pRxCurPkt = NULL; 

        pRxPacketBuf = (PUCHAR)pRxPDCurrent + sizeof(RxPD);
		dbgType = *(UCHAR *)pRxPacketBuf;

		if (dbgType = DBG_TYPE_SMALL)
        {
            HexDump(DBG_RX|DBG_FW, "FWDBG:",
                    (UCHAR *)&pRxPacketBuf + SIZE_OF_DBG_STRUCT,
                    Adapter->ulRxSize);
            DBGPRINT(DBG_RX|DBG_FW, (L"FWDBG::\r\n"));

            // Free this debug packet
            if (pPacket)
                ReturnRxPacketDesc((PVOID)pRxParam, pPacket);
            return;
        }
    }

#endif
*/
    if (Adapter->MediaConnectStatus == NdisMediaStateDisconnected) {
        ///pmkcache: bug#16956 ++
        if (Adapter->bIsReconnectAssociation == TRUE)
        {
            pRxParam->pTmpPendRxNode = pCurrRxNode;
            return;
        }
        ///pmkcache: bug#16956 --
        DBGPRINT(DBG_RX|DBG_ERROR, (L"Not connected, packet was dropped...\n"));
        ReturnRxPacketNode((PVOID)pRxParam, pCurrRxNode);
        goto FuncFinal;
    }

    for (i=0 ; i<pCurrRxNode->UsedPkt ; i++) {
        if (pCurrRxNode->pRxPd[i]->Status & MRVDRV_RXPD_STATUS_OK)
        {
            Adapter->RcvOK++;
            Adapter->DirectedFramesRcvOK++;
            wlan_compute_rssi(Adapter,pCurrRxNode->pRxPd[i]);
        }
        else
        {
            DBGPRINT(DBG_RX | DBG_WARNING,(L"WARNING: frame received with bad status\n"));
            RETAILMSG(1, (L"frame received with bad status\r\n"));
            ReturnRxPacketNode((PVOID)pRxParam, pCurrRxNode);
            goto FuncFinal;
        }
        NDIS_SET_PACKET_STATUS(pCurrRxNode->pPacket[i], pStatus);
    }

    ///PendNode ++
    ///*    
    NdisAcquireSpinLock(&pRxParam->RxCS);
    for (i=0 ; i<pCurrRxNode->UsedPkt ; i++) {
        pRxParam->pRxPendPkts[pRxParam->PRPktCount+i] = pCurrRxNode->pPacket[i]; 

    }
    pRxParam->PRPktCount += pCurrRxNode->UsedPkt;
    pRxParam->pPendingRxNode[pRxParam->PRNdCount++] = pCurrRxNode;    

    //RETAILMSG(1,(L"&&&&&&&&& PKTCOUNT:%d,RxNode:%d\n\r",pRxParam->PRPktCount, pRxParam->PRNdCount));

    //pRxParam->PRNdCount ++;
    //NdisSetEvent(pRxParam->hIndicateEvent);
    SetEvent(pRxParam->hIndicateEvent);

    NdisReleaseSpinLock(&pRxParam->RxCS);
    //*/
    ///PendNode --

FuncFinal:
    return;
}

/* ========================================================================= */
NDIS_STATUS InitRxParam(IN PPVOID ipRxParam, IN PRXINIT pRxInit)
{
	NDIS_STATUS result = NDIS_STATUS_SUCCESS;
	PRX_PARAM	pRxParam;

	pRxParam = *ipRxParam = (PVOID)&RxParam[0];
	NdisZeroMemory(pRxParam, sizeof(RX_PARAM));
	
	pRxParam->pAdapter = pRxInit->pAdapter;
	pRxParam->MrvDrvAdapterHdl = pRxInit->MrvDrvAdapterHdl;
	//pRxParam->isPktPending = FALSE;
	NdisAllocateSpinLock(&pRxParam->RxQueueSpinLock);
	// Build up RxQ
	result = AllocateRxQ(pRxParam);
	if( result != NDIS_STATUS_SUCCESS ){
		goto FuncFinal;
	}
   pRxParam->PktStatus = NDIS_STATUS_RESOURCES;  
  ///PendNode ++
  NdisAllocateSpinLock(&pRxParam->RxCS);
  pRxParam->hIndicateEvent = wlan_create_thread(RxIndicateThread, pRxParam, 102);
  ///PendNode --



FuncFinal:
	return result;
}

NDIS_STATUS	DeinitRxParam(IN PVOID ipRxParam)
{
	NDIS_STATUS 	result = NDIS_STATUS_SUCCESS;
	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;

	NdisFreeSpinLock(&pRxParam->RxQueueSpinLock);
	FreeRxQ(pRxParam);
	
  ///PendNode ++
  wlan_destroy_thread(pRxParam->hIndicateEvent);
  NdisFreeSpinLock(&pRxParam->RxCS);
  ///PendNode --



	
	return result;
}

//VOID SetCurrentPkt(IN PVOID ipRxParam, PNDIS_PACKET	pPacket)
VOID SetCurrentPkt(IN PVOID ipRxParam, IN PPACKET_QUEUE_NODE pRxNode)
{
	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
    //PIF_UPLD_PACKET pUpldBuf = (PIF_UPLD_PACKET)pRxNode->pRxBufVM;
    //PRxPD           pRxPd = (PRxPD)pUpldBuf->Code;
    
	//pRxParam->pRxCurPkt = pRxNode->pPacket;
    //pRxParam->pRxPD1 = pRxPd;
    //pRxParam->ulRxSize = pRxPd->PktLen;
    pRxParam->pCurrRxNode = pRxNode;
	return;
}

//VOID SetRxPd(IN PVOID ipRxParam, IN PRxPD pRxPD)
//{
//	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
//	pRxParam->pRxPD1 = pRxPD;
//	return;
//}


//PPACKET_QUEUE_NODE GetRxPendPkt(IN PVOID ipRxParam)
//{
//	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
//	return pRxParam->pTmpPendRxNode;
//}

VOID IndicateRxPkt(IN PVOID ipRxParam)
{
	NDIS_STATUS        pStatus;
	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
	//PNDIS_PACKET pPacket = pRxParam->pPendedRxPkt;
	PPACKET_QUEUE_NODE  pRxNode = pRxParam->pTmpPendRxNode;
	USHORT i;
	
	pRxParam->pTmpPendRxNode = NULL;
	///Adapter->ulRxByteInLastPeriod += pRxParam->ulRxSize;  
    for (i=0 ; i<pRxNode->UsedPkt ; i++) {
	    NDIS_SET_PACKET_STATUS(pRxNode->pPacket[i], NDIS_STATUS_SUCCESS);
    }

	NdisMIndicateReceivePacket(pRxParam->MrvDrvAdapterHdl, pRxNode->pPacket, pRxNode->UsedPkt);

    for (i=0 ; i<pRxNode->UsedPkt ; i++) {

    	pStatus = NDIS_GET_PACKET_STATUS(pRxNode->pPacket[i]);

    	if ((pStatus == NDIS_STATUS_RESOURCES) || (pStatus == NDIS_STATUS_SUCCESS))
    	{
    	    // return packet
    	    DBGPRINT(DBG_RX|DBG_HELP, (L"Packet returned success or resources...\n"));
    	    ReturnRxPacketDesc(pRxParam, pRxNode->pPacket[i]);  
    	}
    	else
    	{
    	    DBGPRINT(DBG_RX|DBG_ERROR, (L"Packet returned pending...\n"));
    	}
    }

	return;
}

SHORT GetRxPendPktcnt(IN PVOID ipRxParam)
{
	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
	return pRxParam->sNumOutstandingRxPacket;
}


//VOID SetRxSize(IN PVOID ipRxParam, ULONG ulRxSize)
//{
//	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
//	pRxParam->ulRxSize = ulRxSize;
//	return;
//}

//ULONG GetRxSize(IN PVOID ipRxParam)
//{
//	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
//	return pRxParam->ulRxSize;
//}

BOOLEAN	IsPktPending(IN PVOID ipRxParam)
{
	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
	//return (pRxParam->isPktPending;
	return (pRxParam->pTmpPendRxNode == NULL)?(FALSE):(TRUE);
}

//VOID SetPktPendingFlag(IN PVOID ipRxParam, IN BOOLEAN flag)
//{
//	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
//	pRxParam->isPktPending = flag;
//	return;
//}

//PNDIS_PACKET GetRxCurPkt(IN PVOID ipRxParam)
//{
//	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
//	return pRxParam->pRxCurPkt;
//}

VOID RxCheckForHang(IN PVOID ipRxParam)
{
	PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;

	//RETAILMSG(1, (L" RxPendingCount: %d\r\n", GetRxPendPktcnt(ipRxParam)));
	
	return;
}


/*
Description: Update the parameters in RxNode & return the pointer to the packet
*/
PUCHAR UpdateRxNodePacket(IN PVOID ipRxParam, IN PPACKET_QUEUE_NODE pRxNode)
{
    PRX_PARAM	pRxParam = (PRX_PARAM)ipRxParam;
    NDIS_STATUS tStatus;
    PIF_UPLD_PACKET pUpldBuf = (PIF_UPLD_PACKET)pRxNode->pRxBufVM;
    PRxPD           pRxPd = (PRxPD)pUpldBuf->Code;
    ///PUCHAR          pPktBuf = &pUpldBuf->Code[pRxPd->PktPtr];
    PUCHAR          pPktBuf = ((PUCHAR)pRxPd)+pRxPd->PktPtr;
    USHORT          i;

    pRxNode->UsedPkt = 0;
    for (i=0 ; i<RxPKTAggreCnt ; i++) {
        pRxNode->pRxPd[i] = pRxPd;
        NdisAllocateBuffer(&tStatus, 
                        &pRxNode->pRxBuffer[i],
                        pRxParam->RxBufferPoolHandle,
                        pPktBuf,
                        pRxPd->PktLen);
        NdisChainBufferAtFront(pRxNode->pPacket[i],
                            pRxNode->pRxBuffer[i]);
        pRxNode->UsedPkt ++;
        if (pRxPd->NextRxPDPtr == 0) {
            break;
        }
        pRxPd = (PRxPD)(((PUCHAR)pRxPd)+(pRxPd->NextRxPDPtr));
        pPktBuf = ((PUCHAR)pRxPd)+pRxPd->PktPtr;
    }
    return pPktBuf;
}






///PendNode ++
static void RxIndicateThread(PVOID pContext)
{
    PRX_PARAM	pRxParam = (PRX_PARAM)pContext;
    USHORT      i, j;
    //NDIS_STATUS PStatus;
    PPACKET_QUEUE_NODE  pRxNode;
    //BOOLEAN     HasSmallPkts = FALSE;

    /*for (i=0 ; i<pRxParam->PRNdCount ; i++) {
        for (j=0 ; j<pRxParam->pPendingRxNode[i]->UsedPkt; j++) {
            if (pRxParam->pPendingRxNode[i]->PktLen[j] < 1000) {
                HasSmallPkts = TRUE;
            }
        }
    }
    if (HasSmallPkts == TRUE) {
        NdisMSleep(10000);
    }*/ 
     
    //dralee++
    if(pRxParam->PRPktCount==0)
         return; 


    //RETAILMSG(1,(L"RX indicate thread:%d\n\r",GetTickCount()));

    NdisAcquireSpinLock(&pRxParam->RxCS); 
  
    pRxParam->indicateevent = 0;   

    //RETAILMSG(1,(L"indicate:%d\n\r",pRxParam->PRPktCount));
                                                            
    //txdebug_3(pRxParam->pAdapter->pTxParam, pRxParam->PRPktCount);
                   
    NdisMIndicateReceivePacket(pRxParam->MrvDrvAdapterHdl, 
                               pRxParam->pRxPendPkts, 
                               pRxParam->PRPktCount);


    if (pRxParam->PktStatus == NDIS_STATUS_RESOURCES) {
        /* ref: description of "NdisMIndicateReceivePacket" in MSDN:
        
        A deserialized miniport driver must not examine the Status of indicated packets on return of 
        NdisMIndicateReceivePacket. Instead, a deserialized miniport driver must save a packet's Status 
        in a local variable before indicating up the packet descriptor. When NdisMIndicateReceivePacket 
        returns, the miniport driver should check the saved packet Status. 
        - If the miniport driver set the packet's Status to NDIS_STATUS_RESOURCES before indicating up 
            the packet descriptor, it should reclaim the packet descriptor immediately after 
            NdisMIndicateReceivePacket returns, preferably by calling its own MiniportReturnPacket function. 
            In this case, NDIS does not call the miniport driver's MiniportReturnPacket function to return 
            the packet descriptor. 
        - If the miniport driver set the packet's Status to NDIS_STATUS_SUCCESS before indicating up 
            the packet descriptor, the miniport driver must not reclaim the packet descriptor until NDIS 
            subsequently returns the packet descriptor to the miniport driver's MiniportReturnPacket function.
        */
        for (i=0 ; i<pRxParam->PRNdCount ; i++) {
            pRxNode = pRxParam->pPendingRxNode[i];
            for (j=0 ; j<pRxNode->UsedPkt ; j++) {
                NdisUnchainBufferAtFront(pRxNode->pPacket[j], &pRxNode->pRxBuffer[j]);
	            NdisFreeBuffer(pRxNode->pRxBuffer[j]);
            }    

            //RETAILMSG(1,(L"ReturnRxPacketNode 1\n\r"));

            ReturnRxPacketNode(pRxParam, pRxNode); 
  
            //RETAILMSG(1,(L"ReturnRxPacketNode 2\n\r"));
        }
        pRxParam->PRPktCount = pRxParam->PRNdCount = 0;   
        
        //dralee++
        ResetEvent(pRxParam->hIndicateEvent);
    
        
    }
    NdisReleaseSpinLock(&pRxParam->RxCS);
    return;
}
///PendNode --

   










